#include "head.h"

void print_matrix(double matrix[][LENGTH]) {
	//printf("%d %d\n",LENGTH, LENGTH);
	//FILE * plik = fopen("result.txt", "a");
	int i,j;
	for (i = 0; i < LENGTH; i++) {
		for (j = 0; j < LENGTH; j++) {
			//fprintf(plik, "\t%f", matrix[i][j]);
			printf("\t%f", matrix[i][j]);
		}
		//fprintf(plik, "\n");
		printf("\n");
	}
	//fclose(plik);
}

double determinant(int n, double mat[n][n]) {
	int i,j,i_count,j_count, count=0;
	double array[n-1][n-1], det=0.0;
 
	if(n < 1) {
		puts("Error");
		exit(1);
	}
	if(n == 1) {
		return mat[0][0];
	}
	if(n == 2) {
		return (mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0]);
	} 
	for(count = 0; count < n; count++){
		i_count=0;
		for(i = 1; i < n; i++) {
			j_count=0;
			for(j = 0; j < n; j++) {
				if(j == count) {
					continue;
				}
				array[i_count][j_count] = mat[i][j];
				j_count++;
			}
			i_count++;
		}
		det += pow(-1, count) * mat[0][count] * determinant(n - 1, array);
	}
	return det;
}

void task_matrix(struct task t) {
	print_matrix(t.matrix);
	double result = determinant(LENGTH, t.matrix);
	/*FILE * plik = fopen("result.txt","a");
	fprintf(plik, "Determinant: %.2f\n", result);
	fclose(plik);*/
	printf("Determinant: %.2f\n", result);
	fflush(stdout);
}

union semun {
	int val;
	struct semid_ds * buffer;
	ushort * array;
};

int main(int argc, char ** argv) {
	key_t key_sem, key_full, key_empty, key_sha;
	key_sem = ftok("./producer.c", 16);
	key_full = ftok("./head.h", 32);
	key_empty = ftok("./head.h", 64);
	key_sha = ftok("./", 128);
	int id_sem, sem_full, sem_empty, id_sha, sem_count = 5, task_count = 5, producer_count = 10;
	id_sem = semget(key_sem, sem_count, IPC_CREAT | 0666);
	sem_full = semget(key_full, 1, IPC_CREAT | 0666);
	sem_empty = semget(key_empty, 1, IPC_CREAT | 0666);
	id_sha = shmget(key_sha, sizeof(struct task)*task_count, IPC_CREAT | 0666);
	if (id_sem == -1 || sem_full == -1 || sem_empty == -1 || id_sha == -1) {
		perror("semget/shmget");
		return -1;
	}
	struct task * tasks;
	if ((tasks = shmat(id_sha, (void *)0, 0)) == NULL) {
		perror("shmat");
		return -2;
	}
	union semun init;
	init.val = 1;
	int i;
	for (i = 0; i < task_count; i++) {
		if (semctl(id_sem, i, SETVAL, init) == -1) {
			perror("semctl");
			return -3;
		}
	}
	for (i = 0; i < producer_count; i++) {
		pid_t pid = fork();
		if (pid == 0) {
			break;
		} else if (pid < 0) {
			perror("fork");
			return -4;
		}
	}
	srand(time(NULL));
	while (1) {
		struct task tmp;
		struct sembuf sem_tmp1, sem_tmp2;
		sem_tmp1.sem_num = 0;
		sem_tmp1.sem_flg = 0;
		sem_tmp1.sem_op = -1;
		if (semop(sem_empty, &sem_tmp1, 1) == -1) {
			perror("semop 1");
			//return -5;
		}
		for (i = 0; i < task_count; i++) {
			sleep(1);
			sem_tmp2.sem_flg = 0;
			sem_tmp2.sem_num = i;
			sem_tmp2.sem_op = -1;
			if (semop(id_sem, &sem_tmp2, 1) != -1) {	
				if (tasks[i].operation < 1) {
					memcpy(&tmp, &tasks[i], sizeof(struct task));
					tasks[i].operation = 1;
					printf("Operacja pobrana do wykonania\n");
					sem_tmp2.sem_flg = 0;
					sem_tmp2.sem_num = i;
					sem_tmp2.sem_op = 1;
					if (semop(id_sem, &sem_tmp2, 1) == -1) {
						perror("semop 3");
						//return -6;
					}
					sem_tmp1.sem_num = 0;
					sem_tmp1.sem_flg = 0;
					sem_tmp1.sem_op = 1;
					if (semop(sem_full, &sem_tmp1, 1) == -1) {
						perror("semop 4");
						//return -7;
					}
					task_matrix(tmp);
					break;
				}
			} else { 
				perror("semop 2");
				//return -8;				
			}
			sem_tmp2.sem_flg = 0;
			sem_tmp2.sem_num = i;
			sem_tmp2.sem_op = 1;
			if (semop(id_sem, &sem_tmp2, 1) == -1) {
				perror("semop 5");
				//return -9;
			}
		}
	}
	return 0;
}
